iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Kubernetes

Kubernetes GPU 工作負載工程:排程、資源隔離、推論服務與可觀測性系列 第 6

Day 06|把工作負載送到對的 GPU Node:Label、NodeSelector 與 Affinity

  • 分享至 

  • xImage
  •  

Pod 申請 nvidia.com/gpu: 1,只代表需要一個可分配的 GPU 資源,沒有表達 GPU 型號、VRAM 等級、機房位置或本機儲存需求。當叢集只有一種 GPU 時,這個限制不明顯;節點規格開始分化後,排程成功不再代表工作負載進入合適的節點。

Labels、nodeSelector 與 node affinity 的工作,就是把節點能力和工作負載需求連接起來。

Label 描述穩定能力

Label 是附加在 Kubernetes 物件上的 key-value 資訊。套用在 Node 時,可以描述排程需要知道的特徵,例如:

  • GPU 供應商或產品系列。
  • VRAM 等級。
  • 是否具備高速本機磁碟。
  • 推論、訓練或批次運算用途。
  • region、zone 或故障域。

自訂 label 最好使用組織擁有的 DNS prefix,避免和平台或第三方元件使用的 key 衝突。例如:

platform.example.com/accelerator-class=l40s
platform.example.com/vram-tier=large
platform.example.com/workload=inference

Label 應描述相對穩定且可驗證的事實。GPU utilization、目前空閒 VRAM、queue depth 等即時數值不適合由人工持續改寫成 label;變更頻率過高不但容易產生漂移,也會把排程決策建立在過期狀態上。

nodeSelector:最簡單的硬性條件

nodeSelector 是最直接的節點選擇方式。Pod 只會被排到同時符合所有指定 label 的節點。

apiVersion: v1
kind: Pod
metadata:
  name: inference-worker
spec:
  nodeSelector:
    platform.example.com/workload: inference
    platform.example.com/vram-tier: large
  containers:
    - name: server
      image: example/inference-server:1.0
      resources:
        limits:
          nvidia.com/gpu: 1

這種寫法容易閱讀,適合條件少而且都是必要限制的情況。缺點是只能做簡單的等值比對,也無法表達「A 或 B」或「優先選 A,沒有 A 也可接受 B」。

Node affinity:區分必要條件與偏好

Node affinity 提供較完整的選擇語法,最重要的是能分成 hard requirement 與 soft preference。

requiredDuringSchedulingIgnoredDuringExecution 是必要條件。沒有符合節點時,Pod 會停在 Pending:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: platform.example.com/workload
              operator: In
              values: ["inference"]
            - key: platform.example.com/vram-tier
              operator: In
              values: ["medium", "large"]

同一個 nodeSelectorTerm 內的 expressions 採 AND;多個 terms 之間採 OR。這個細節若理解錯誤,可能讓可選節點比預期更多或更少。

preferredDuringSchedulingIgnoredDuringExecution 則是偏好。Scheduler 會把符合規則的權重加入節點分數,但沒有符合節點時仍可排到別處:

affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
            - key: platform.example.com/local-model-cache
              operator: In
              values: ["ready"]

模型 cache、本機磁碟或較低成本節點通常適合做偏好;驅動相容性、必要 VRAM 等級與法規要求則應做硬性條件。

不要把型號寫死在每個應用

直接要求某個精確 GPU 型號很方便,但會讓 Deployment 與基礎設施緊密耦合。叢集新增可相容的新型號後,每個工作負載都要修改 manifest,維護成本會快速增加。

較穩定的做法是先定義能力層級,例如 vram-tier=largeaccelerator-class=inference,再由平台團隊維護各節點屬於哪個等級。只有當核心功能確實依賴特定架構、指令集或測試認證時,才直接指定產品型號。

抽象 label 也不能只靠命名。每個等級都要有清楚定義,例如最低 VRAM、支援的 driver、允許的工作負載與效能基準,否則不同管理者會套用不同標準。

IgnoredDuringExecution 容易被忽略

名稱中的 IgnoredDuringExecution 表示規則主要在排程當下生效。Pod 已經進入節點後,即使 label 被移除或改值,現有 Pod 通常不會因此自動搬移。

因此,修正錯誤 label 只能避免新的錯誤 placement,不能取代對既有 Pod 的盤點與重建。節點能力若發生重大變化,應搭配 cordon、drain、重新部署或自動化控制器處理。

Label governance 是排程的一部分

工作負載越依賴 label,label 的正確性就越接近控制面的一部分。至少要建立以下規則:

  • 誰能建立、修改與移除節點 label。
  • Label 值來自人工設定、硬體探索元件,還是雲端供應商。
  • 變更後如何驗證節點真實能力。
  • 如何偵測缺少、拼錯、過期或互相矛盾的 label。
  • 哪些 label 屬於安全或隔離邊界。

若 label 會把高權限工作負載導向特定節點,不應讓不受信任的 kubelet 任意修改。Kubernetes 提供 NodeRestriction admission plugin 與受保護的 label prefix,可降低節點自行偽造隔離屬性的風險。

驗證排程規則

套用規則後,不要只確認 Pod 進入 Running。驗證至少包含:

  1. 列出符合條件的候選節點,確認數量與預期一致。
  2. 建立 Pod 後檢查實際 placement 與 scheduling events。
  3. 故意使用不存在的硬性條件,確認 Pod 保持 Pending 且原因清楚。
  4. 移除偏好節點,確認 Pod 仍能在可接受的節點啟動。
  5. 變更 label 後,確認新舊 Pod 的行為符合生命週期預期。

硬性條件過多會降低可排程性;偏好過多則可能互相稀釋,讓結果難以理解。每一條規則都應能回答:不符合時,是必須拒絕,還是可以降級?

結論

Label 負責描述節點能力,nodeSelector 適合簡單硬限制,node affinity 則能表達集合、否定、存在性與加權偏好。真正可維護的設計不在於寫出最複雜的規則,而是把必要條件和最佳化偏好分開,並讓 label 有明確來源、定義與維護責任。

把工作負載送到合適的 GPU 節點後,下一個問題是如何避免一般 Pod 佔用昂貴資源。下一篇將處理 Taints 與 Tolerations。


參考資料


上一篇
Day 05|GPU Request 的第一個限制:一張卡不是 1GB、2GB 這樣分
下一篇
Day 07|Taints/Tolerations:別讓一般 Pod 把 GPU 節點吃掉
系列文
Kubernetes GPU 工作負載工程:排程、資源隔離、推論服務與可觀測性10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言